using System;
using System.Collections;
using Castle.MonoRail.Framework;
using Castle.MonoRail.Framework.Helpers;
using Castle.MonoRail.ActiveRecordSupport;
using Castle.ActiveRecord;
using NHibernate.Expression;
using DecisionesInteligentes.iEvalua.Models;

namespace DecisionesInteligentes.iEvalua.Web.Controllers
{
	[Layout("default"), Rescue("general")]
	public class BaseController<T> : ARSmartDispatcherController where T: ActiveRecordValidationBase<T> 
	{
		private User currentUser;
		
		public User CurrentUser {
			set {
				currentUser = value;
			}
			get {
				if (currentUser == null) {
					currentUser = (User)Context.CurrentUser;
				}
				
				return currentUser;
			}
		}
		
		public virtual void Index()
		{
			List(null, null);
		}
		
		public virtual void New()
		{	
		}
		
		public virtual void Create([ARDataBind("entity")] T entity)
		{
			CreateNew(entity);
		}
		
		public virtual void Edit()
		{
			if(PropertyBag["entity"] == null)
			{
				RedirectToAction("Index");
			}
		}
		
		public virtual void Edit(int id)
		{
			Load(id);
		}
		
		public virtual void View(int id)
		{
			Load(id);
		}
		
		public virtual void Save([ARDataBind("entity")] T entity)
		{
			Update(entity);
		}
		
		private Application application = null;
		
		public Application Application
		{
			get
			{
				if(application == null)
				{	
					Application app =  Models.Application.FindByName("iEvalua");
					if(app == null)
						return new Application();
					else
						application = app;
				}
				
				return application;
			}
		}
		
		protected string[] GetErrorSummary(T entity)
		{
			string[] errors = new string[0];
			
			if(base.HasValidationError(entity))
			{
				errors = base.GetErrorSummary(entity).ErrorMessages;
			}else if(!entity.IsValid())
			{
				errors = entity.ValidationErrorMessages;
			}
			
			return errors;
		}
		
		protected void SetPostActionEnvironment(T entity, string action, string message, string[] error, string parameters)
		{
			if(entity != null)
				PropertyBag["entity"] = entity;

			if(!String.IsNullOrEmpty(message))
				Flash["message"] = message;

			if(error != null)
				Flash["error"] = error;
				
			if(!String.IsNullOrEmpty(action))
			{
				if(!String.IsNullOrEmpty(parameters))
					RedirectToAction(action, parameters);
				else
					RedirectToAction(action);
			}
		}
		
		protected bool HasValidationError(T entity)
		{
			return base.HasValidationError(entity) | !entity.IsValid();
		}
		
		protected virtual string EntityName() 
		{
			return typeof(T).Name;
		}
		
		protected virtual void SetupView()
		{
		}
		
		protected virtual void List(Order[] order, params ICriterion[] criteria)
		{
			List(10, order, criteria);
		}
		
		protected virtual void List(int pageSize, Order[] order, params ICriterion[] criteria)
		{
			PropertyBag["entities"] = 
				PaginationHelper.CreatePagination(this, (IList)T.FindAll(criteria), pageSize);
		}
		
		protected virtual void CreateNew(T entity)
		{
			if(!HasValidationError(entity))
			{
				try
				{
					entity.Create();
					
					SetPostActionEnvironment(null, "Edit", "A new " + EntityName() + " has been created",
						null, "id=" + ((IEntity)entity).GetId());
						
				}catch(Exception ex)
				{
					SetPostActionEnvironment(entity, "New", EntityName() +  " was not saved due some errors.",
						new string[] { ex.Message }, null);
				}
			}else
			{
				SetPostActionEnvironment(entity, "New", EntityName() + " has some invalid data",
					GetErrorSummary(entity), null);
			}
		}
		
		protected virtual void Update(T entity)
		{
			if(!HasValidationError(entity))
			{
				try
				{
					entity.Update();
					
					SetPostActionEnvironment(null, "Edit", EntityName() + " has been saved",
						null, "id=" + ((IEntity)entity).GetId());
						
				}catch(Exception ex)
				{
					SetPostActionEnvironment(entity, "Edit", EntityName() +  " was not saved due some errors.",
						new string[] { ex.Message }, null);
				}
			}else
			{
				SetPostActionEnvironment(entity, "Edit", EntityName() + " has some invalid data",
					GetErrorSummary(entity), null);
			}
		}
		
		protected virtual void Load(int id)
		{
			T entity = default(T);
			try
			{
				entity = T.Find(id);
				
				if(entity != null)
				{
					PropertyBag["entity"] = entity;
				}else
				{
					SetPostActionEnvironment(null, "Index", "Failed to load " + EntityName(),
						new string[] { EntityName() + " not found" }, null);
				}
			}catch(Exception ex)
			{
				SetPostActionEnvironment(null, "Index", "Failed to load " + EntityName(),
					new string[] { ex.Message }, null);
			}
		}
	}
}